#define _GNU_SOURCE 1
#include <stdio.h>
#include "net.h"
#include <unistd.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>

int tcp_main()
{
	printf("%s\n", net_version());
	int sockfd = net_tcp_client_init("10.184.148.220", 12500, NULL);
	struct stat stat_buf;
	ssize_t ret = 0;
	clock_t start = 0;
	clock_t end = 0;
	printf("sockfd[%d]\n", sockfd);
	if (sockfd < 0)
	{
		return 0;
	}

	int fd = open("./test.c", O_RDONLY);
	if (fd < 0)
	{
		close(sockfd);
		return 0;
	}
	fstat(fd, &stat_buf);
	start = clock();
	write(sockfd, "123456", sizeof("123456"));

	ret = sendfile(sockfd, fd, NULL, stat_buf.st_size);
	end = clock();
	printf("%ld = [%.8lf]\n", ret, ((double)(end - start)) / CLOCKS_PER_SEC);

	close(sockfd);
	close(fd);

	return 0;
}

int tcp_main1()
{
	printf("%s\n", net_version());
	int sockfd = net_tcp_client_init("10.184.148.220", 12500, NULL);
	struct stat stat_buf;
	char buf[5000] = {0};
	ssize_t ret = 0;
	clock_t start = 0;
	clock_t end = 0;

	printf("sockfd[%d]\n", sockfd);
	if (sockfd < 0)
	{
		return 0;
	}

	int fd = open("./test.c", O_RDONLY);
	if (fd < 0)
	{
		close(sockfd);
		return 0;
	}
	fstat(fd, &stat_buf);

	start = clock();

	write(sockfd, "123456", sizeof("123456"));

	ret = read(fd, buf, stat_buf.st_size);
	if (ret != stat_buf.st_size)
	{
		close(sockfd);
		close(fd);
		return -1;
	}

	ret = write(sockfd, buf, ret);

	end = clock();

	printf("%ld = [%.8lf]\n", ret, ((double)(end - start)) / CLOCKS_PER_SEC);

	close(sockfd);
	close(fd);

	return 0;
}

int udp_main()
{
	net_version();
	printf("udp_main\n");
	struct sockaddr_in remote_addr;
	struct sockaddr_in local_addr;
	int remote_addr_len = sizeof(remote_addr);
	int local_addr_len = sizeof(local_addr);

	int sockfd = net_udp_client_init();
	printf("sockfd[%d]\n", sockfd);

	if (sockfd < 0)
	{
		return 0;
	}

	bzero(&remote_addr, sizeof(remote_addr));
	remote_addr.sin_family = AF_INET;
	remote_addr.sin_port = htons(12500);
	remote_addr.sin_addr.s_addr = inet_addr("10.184.148.220");

	bzero(&local_addr, local_addr_len);
	int ret = getsockname(sockfd, (struct sockaddr *)&local_addr, &local_addr_len);
	printf("[%s:%d]ret[%d]\n", inet_ntoa(local_addr.sin_addr), ntohs(local_addr.sin_port), ret);

	char msg[64] = "HELLO client!";
	sendto(sockfd, msg, strlen(msg), 0, (struct sockaddr *)&remote_addr, remote_addr_len);
	printf("[%s:%d]%s\n", inet_ntoa(remote_addr.sin_addr), ntohs(remote_addr.sin_port), msg);

	recvfrom(sockfd, msg, 64, 0, (struct sockaddr *)&local_addr, &local_addr_len);
	printf("[%s:%d]%s\n", inet_ntoa(local_addr.sin_addr), ntohs(local_addr.sin_port), msg);

	close(sockfd);

	return 0;
}

int udp_server_main()
{
	// udp_main();
	int sockfd = -1;
	struct sockaddr_in client;
	int client_len = sizeof(client);

	sockfd = net_udp_server_init(12563);
	printf("sockfd[%d]\n", sockfd);
	if (sockfd < 0)
	{
		return 0;
	}

	bzero(&client, sizeof(client));
	client.sin_family = AF_INET;
	client.sin_port = htons(12500);
	client.sin_addr.s_addr = inet_addr("10.184.148.220");

	char msg[64] = "HELLO client!";
	sendto(sockfd, msg, strlen(msg), 0, (struct sockaddr *)&client, client_len);
	printf("[%s:%d]%s\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port), msg);

	recvfrom(sockfd, msg, 64, 0, (struct sockaddr *)&client, &client_len);
	// printf("[%s:%d]%s\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port), msg);
	write(1, msg, strlen(msg));

	close(sockfd);

	return 0;
}

int tcps_main()
{
	int sockfd = net_tcp_server_init(12501, 5);
	struct sockaddr_in client;
	int client_len = sizeof(client);
	printf("sockfd[%d]\n", sockfd);
	if (sockfd < 0)
	{
		return 0;
	}
	int fd = -1;
	char buf[64] = {0};
	while (1)
	{
		fd = accept(sockfd, (struct sockaddr *)&client, &client_len);

		int pipefd[2];
		pipe(pipefd);

		splice(fd, NULL, pipefd[1], NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE);

		splice(pipefd[0], NULL, fd, NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE);

		close(pipefd[0]);
		close(pipefd[1]);

		sleep(1);

		close(fd);
		break;
	}
	close(sockfd);
	return 0;
}

int tcps_main1()
{
	int sockfd = net_tcp_server_init(12501, 5);
	struct sockaddr_in client;
	int client_len = sizeof(client);
	ssize_t ret = 0;
	printf("sockfd[%d]\n", sockfd);
	if (sockfd < 0)
	{
		return 0;
	}
	int fd = -1;
	char buf[64] = {0};
	while (1)
	{
		fd = accept(sockfd, (struct sockaddr *)&client, &client_len);

		sleep(1);
		ret = splice(fd, NULL, 1, NULL, 256, SPLICE_F_MORE | SPLICE_F_MOVE);

		printf("%d===[%ld]\n", fd, ret);

		close(fd);
		break;
	}
	close(sockfd);
	return 0;
}

int test_main()
{
	uint64_t file_size = 1 * 1024 * 1024ULL;
	int fd = open("tmp.txt", O_RDWR | O_CREAT, 0666);
	if (fd < 0)
	{
		printf("fd < 0");
		return -1;
	}

	// 不支持 NTFS 文件系统
	int ret = posix_fallocate(fd, 0, file_size);
	if (ret < 0)
	{
		printf("ret = %d, errno = %d,  %s\n", ret, errno, strerror(errno));
		return -1;
	}

	printf("fallocate create %.2fG file\n", file_size / 1024 / 1024 / 1024.0);

	write(fd, "test", 4);

	close(fd);
	return 0;
}

int create_file()
{
	uint64_t file_size = 1 * 1024 * 1024ULL;
	FILE *fd = fopen("test.bin", "wb+");
	if (fd == NULL)
	{
		printf("fd < 0");
		return -1;
	}

	off_t len = fseek(fd, file_size, SEEK_SET);
	printf("len[%ld]\n", len);
	fwrite("test", 1, 4, fd);
	fclose(fd);
	return 0;
}

void ipv6_tcp_client()
{
	struct timeval timeout;
	timeout.tv_sec = 5;
	timeout.tv_usec = 0;
	int sockfd = net_tcp_client_init_v6("fe80::5ae9:aa1b:8f6a:2b5b%13", 12500, &timeout);
	struct sockaddr_in6 local_addr;
	bzero(&local_addr, sizeof(local_addr));
	int local_addr_len = sizeof(local_addr);
	printf("sockfd[%d]\n", sockfd);
	if (sockfd < 0)
	{
		printf("sockfd < 0 [%d]\n", sockfd);
		return;
	}
	char buf[512] = {0};
	write(sockfd, "123456", sizeof("123456"));
	read(sockfd, buf, 512);
	write(1, buf, strlen(buf));

	int ret = getsockname(sockfd, (struct sockaddr *)&local_addr, &local_addr_len);
	printf("[%s:%d]ret[%d]\n", inet_ntop(AF_INET6, &local_addr.sin6_addr, buf, 512), ntohs(local_addr.sin6_port), ret);

	close(sockfd);
	return;
}

int v6_client_main()
{
	int sock;
	struct sockaddr_in6 serv_addr;
	char buffer[1024] = {0};

	// 创建socket
	sock = socket(AF_INET6, SOCK_STREAM, 0);
	if (sock < 0)
	{
		perror("Socket creation failed");
		exit(EXIT_FAILURE);
	}

	// 指定服务器地址和端口
	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin6_family = AF_INET6;
	serv_addr.sin6_port = htons(12500); // 假设服务器端口为8080
	inet_pton(AF_INET6, "::1", &serv_addr.sin6_addr);

	// 连接到服务器
	if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
	{
		printf("%d, %s\n", errno, strerror(errno));
		perror("Connection failed");
		exit(EXIT_FAILURE);
	}

	// 发送数据
	send(sock, "Hello, server!", 14, 0);
	printf("Message sent\n");

	// 接收数据
	int bytesReceived = recv(sock, buffer, 1024, 0);
	printf("Message received: %s\n", buffer);

	// 关闭socket
	close(sock);
	return 0;
}

int ipv6_tcp_server()
{
	int sockfd = net_tcp_server_init_v6(12500, 5);
	struct sockaddr_in6 addr;
	char buf[64] = "hello!";
	char ip[128];

	printf("scokfd[%d]\n", sockfd);

	while (1)
	{
		bzero(&addr, sizeof(addr));
		int len = sizeof(addr);
		int fd = accept(sockfd, &addr, &len);
		if (fd < 0)
		{
			break;
		}
		printf("[%s:%d]\n", inet_ntop(AF_INET6, &addr.sin6_addr, ip, 128), ntohs(addr.sin6_port));
		read(fd, buf, strlen(buf));

		write(fd, "hello, hellov!", 15);

		close(fd);
		break;
	}

	close(sockfd);

	return 0;
}

// 函数用于计算两个字符串之间的Levenshtein距离
int levenshteinDistance(const char *s1, const char *s2)
{
	int len1 = strlen(s1);
	int len2 = strlen(s2);

	printf("len1[%s] = %d, len2[%s] = %d\n", s1, len1, s2, len2);

	// 创建一个二维数组来保存中间结果
	int **dp = (int **)malloc((len1 + 1) * sizeof(int *));
	for (int i = 0; i <= len1; i++)
	{
		dp[i] = (int *)malloc((len2 + 1) * sizeof(int));
	}

	// 初始化边界条件
	for (int i = 0; i <= len1; i++)
	{
		dp[i][0] = i;
	}
	for (int j = 0; j <= len2; j++)
	{
		dp[0][j] = j;
	}

	// 填充dp数组
	for (int i = 1; i <= len1; i++)
	{
		for (int j = 1; j <= len2; j++)
		{
			if (s1[i - 1] == s2[j - 1])
			{
				dp[i][j] = dp[i - 1][j - 1];
				// printf("(%d, %d) == [%d]\n", i, j, dp[i][j]);
			}
			else
			{
				int replace = dp[i - 1][j - 1] + 1;
				int insert = dp[i][j - 1] + 1;
				int delete = dp[i - 1][j] + 1;
				dp[i][j] = (replace < insert) ? ((replace < delete) ? replace : delete) : ((insert < delete) ? insert : delete);
				// printf("(%d, %d) == [%d]\n", i, j, dp[i][j]);
			}
		}
	}
	int result = dp[len1][len2];
	// 释放分配的内存
	for (int i = 0; i <= len1; i++)
	{
		free(dp[i]);
	}
	free(dp);

	// 返回最终的结果
	// return dp[len1][len2];
	return result;
}

void levenshteinDistance_test()
{
	const char *str[] = {
		"粤BD00660",
		"粤BD00661",
		"粤BD00611",
		"粤BD00111",
		"粤BD01111",
		"粤BD11111",
		"粤AA00660",
		"粤AA11111",
		"甘AA11111",
		"甘BD00660",
		"粤B00660",
	};
	for (int i = 1; i < sizeof(str)/sizeof(str[0]); i++)
	{
		printf("ret = %d\n", levenshteinDistance(str[0], str[i]));
	}
	
}

int main(int argc, char *argv[])
{
	// udp_main();
	// udp_server_main();
	// tcps_main();
	// tcp_main();
	// test_main();
	// create_file();

	// ipv6_tcp_client();
	// ipv6_tcp_server();
	// v6_main();
	// tcps_main();
	levenshteinDistance_test();

	return 0;
}